package ink.metoo.gude.module.websocket.service.impl

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import ink.metoo.gude.module.security.domain.ddl.User
import ink.metoo.gude.module.security.repository.UserRepository
import ink.metoo.gude.model.TopicConst
import ink.metoo.gude.module.websocket.domain.ddl.Message
import ink.metoo.gude.module.websocket.domain.model.TextMessage
import ink.metoo.gude.module.websocket.domain.vo.PublicMessageVO
import ink.metoo.gude.module.websocket.repository.MessageRepository
import ink.metoo.gude.module.websocket.service.AiService
import ink.metoo.gude.module.websocket.service.BotService
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder
import org.springframework.messaging.simp.SimpMessagingTemplate
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import kotlin.text.startsWith

@Service
class BotServiceImpl(
    private val aiService: AiService,
    private val userRepository: UserRepository,
    private val messageTemplate: SimpMessagingTemplate,
    private val messageRepository: MessageRepository,
    jackson2ObjectMapperBuilder: Jackson2ObjectMapperBuilder,
) : BotService {

    val objectMapper: ObjectMapper = jackson2ObjectMapperBuilder.build()

    val bot: User by lazy {
        userRepository.findByEmail("Bot")!!
    } 

    @Transactional
    override fun doCommand(senderSessionId: String, text: String) {
        if (!text.startsWith("/")) {
            return
        }
        when {
            text.startsWith(COMMAND_AI) -> doAiCommand(senderSessionId, text.replace(COMMAND_AI, "").trimStart())
        }
    }

    fun doAiCommand(senderSessionId: String, text: String) {
        val answer = aiService.call(text)
        val msg = Message()
        msg.type = Message.Type.TEXT
        val content = TextMessage()
        content.text = answer
        content.template = TextMessage.TemplateType.MARKDOWN
        msg.content = objectMapper.writeValueAsString(content)
        msg.creator = bot
        messageRepository.save(msg)
        val payload = PublicMessageVO()
        payload.fromMessage(msg)
        payload.content = objectMapper.readValue<Map<String, Any>>(msg.content.toString())
        messageTemplate.convertAndSend(TopicConst.PUBLIC_TOPIC, payload)
    }
    
    companion object {
        
        const val COMMAND_AI = "/ai"
        
    }

}